
#ifndef CDN_SERVER_FILE_MANAGER_H
#define CDN_SERVER_FILE_MANAGER_H


#define CDN_STREAMING_RATE_STD_MBPS 3750000u

#ifdef FAKE_DATA
#define CDN_FILE_FAKE_LEN (fw_file_size_t)(499892ull*3600ull*24ull*7ull)
#endif


struct CdnFileRecord {
    string cdn_file_transfer_id;
    string cdn_file_transfer_path;
    string cdn_file_subname;
    fw_file_size_t cdn_file_len;
    long cdn_file_rate;//mbps
};

struct CdnDiskStream {
    ifstream *file_stream_sys;
    CdnFileRecord *cdn_file; 
    fw_file_size_t pos;
    CdnDiskStream(ifstream *inp, CdnFileRecord *cf, fw_file_size_t offset) : 
      file_stream_sys(inp), cdn_file(cf), pos(offset) {} 
    ~CdnDiskStream() {
        file_stream_sys->close();
        delete file_stream_sys;
    }
    bool ReadFileBlock(char *buf, size_t rlen);
    bool Seek(fw_file_size_t abs_pos);
    fw_file_size_t GetAbsPos() { return pos; }
};

struct CdnNodeRecord {
    string transfer_port;
};

typedef map<string, CdnFileRecord*>::value_type CdnFileListRecord;

class FileManager {
    public:
        void GetFileLocation(string &filename, string &transfer_port);
        CdnFileRecord *GetFileObjWithId(const string &transfer_id);
        CdnFileRecord *GetFileObjWithName(const string &filename);
        CdnDiskStream *OpenDiskStream(CdnFileRecord *cdn_file, fw_file_size_t pos);
        void CloseDiskStream(CdnDiskStream *disk_stream);
        FileManager();
        ~FileManager();
#ifdef FAKE_DATA
        bool isFakeStream(CdnDiskStream *dstream) {
            return dstream == fake_stream;
        }
        bool isFakeFile(CdnFileRecord *dfile) {
            return dfile == fake_file;
        }
#endif
    private:
        vector<CdnNodeRecord*> server_nodes;
#ifdef FAKE_DATA
        CdnFileRecord *fake_file;
        CdnDiskStream *fake_stream; 
#endif
        map<string, CdnFileRecord*> file_list; //get file with FileName
        map<string, CdnFileRecord*> file_list_index;//get file with TransferId
        size_t curr_node_id; //node that the next request should go to
};



#endif
